package com.zys.zys_mybatis;

import com.zys.zys_mybatis.utils.LocalDruidUtil;

import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.Objects;

/**
 * @BelongsProject: ZYSMybatis
 * @BelongsPackage: com.zys.zys_mybatis
 * @Author: ZYS
 * @CreateTime: 2024-05-29  18:01
 * @Description: TODO
 */
public class MapperProxyFactory2 {
    public MapperProxyFactory2() {
        //连接初始化，让第一次查询更快
        new LocalDruidUtil();
    }

    public <T> T getMapper(Class<T> mapperInterface) {
        Object o = null;
        o = Proxy.newProxyInstance(
                MapperProxyFactory2.class.getClassLoader(),
                new Class[]{mapperInterface},
                (proxy, method, args) -> {
                    //从注解中获得sql语句
                    String sql0 = getSQL(method);
                    //获取数据库连接、预编译对象、结果集
                    Connection connection = LocalDruidUtil.getConnection();
                    PreparedStatement preparedStatement = null;
                    ResultSet resultSet = null;
                    //获得sql执行器
                    SqlExecuteHandler2 sqlExecuteHandler = new SqlExecuteHandler2(method, args, sql0, connection);
                    //判断sql语句类型，分为有insert、delete、update、select，并执行得到执行结果
                    switch (Objects.requireNonNull(sql0).substring(0, 6)) {
                        case "insert":
                        case "delete":
                        case "update": {
                            //影响行数
                            int affectedRows = 0;
                            try {
                                preparedStatement = sqlExecuteHandler.parseSql();
                                affectedRows = preparedStatement.executeUpdate();
                                System.out.println(affectedRows);
                                return affectedRows;
                            } catch (Exception e) {
                                throw new RuntimeException(e);
                            } finally {
                                assert preparedStatement != null;
                                preparedStatement.close();
                                connection.close();
                            }
                        }
                        case "select": {
                            try {
                                //获得返回结果集
                                preparedStatement = sqlExecuteHandler.parseSql();
                                resultSet = preparedStatement.executeQuery();
                                //获取返回对象类型
                                Class<?> returnType = method.getReturnType();
                                //获得结果集映射器
                                ResultMappingHandler resultMappingHandler = new ResultMappingHandler(resultSet, returnType, method);
                                //返回映射结果
                                return resultMappingHandler.getResult();
                            } catch (Exception e) {
                                throw new RuntimeException(e);
                            } finally {
                                LocalDruidUtil.closeResource(resultSet, preparedStatement, connection);
                            }
                        }
                        default:
                            //其他语句,抛出异常
                            throw new RuntimeException("不支持的sql语句");
                    }
                }
        );
        return (T) o;
    }

    private String getSQL(Method method) {
        if (method.isAnnotationPresent(Select.class)) {
            return method.getAnnotation(Select.class).value();
        }else if (method.isAnnotationPresent(Insert.class)) {
            return method.getAnnotation(Insert.class).value();
        }else if (method.isAnnotationPresent(Update.class)) {
            return method.getAnnotation(Update.class).value();
        }else if (method.isAnnotationPresent(Delete.class)) {
            return method.getAnnotation(Delete.class).value();
        }else {
            throw new RuntimeException("该方法没有注解");
        }
    }

}
